import os
import subprocess

import shutil
from datetime import datetime
from xls2xlsx import XLS2XLSX
from pdf2docx import parse as pdf_parse


def ensure_dir(path):
    """确保目录存在"""
    os.makedirs(path, exist_ok=True)


def traverse_dir(path, tails, file_info_ls=None):
    """
    遍历目录，返回符合后缀要求的文件列表
    :param path: 起始目录
    :param tails: 允许的文件后缀列表（不区分大小写）
    :param file_info_ls: 用于递归存储结果
    :return: [(文件路径, 文件名不含后缀), ...]
    """
    os.makedirs(path, exist_ok=True)
    if file_info_ls is None:
        file_info_ls = []
    for item in os.listdir(path):
        item_path = os.path.join(path, item)
        if os.path.isdir(item_path):
            traverse_dir(item_path, tails, file_info_ls)
        else:
            if item.startswith('~$'):
                continue
            parts = item.split('.')
            if len(parts) < 2:
                continue
            ext = parts[-1].lower()
            if tails is None or ext in tails:
                file_info_ls.append((item_path, '.'.join(parts[:-1])))
    return file_info_ls


def print_log(message):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"{timestamp} : {message}")


def run_unoconv(command_args, success_msg, file_path):
    try:
        subprocess.run(command_args, check=True)
        print_log(f"{file_path} {success_msg}")
        return True
    except subprocess.CalledProcessError as e:
        print_log(f"转换失败: {e}")
        return False


def move_file(src, dst_dir):
    ensure_dir(dst_dir)
    shutil.move(src, os.path.join(dst_dir, os.path.basename(src)))


def convert_doc_to_docx(data_dir, converted_dir):
    doc_files = traverse_dir(data_dir, ['doc'])
    docx_files = traverse_dir(data_dir, ['docx'])
    print_log("DOC 转 DOCX..")
    output_dir = os.path.join(converted_dir, "doc2docx_files")
    ensure_dir(output_dir)
    ensure_dir(os.path.join(converted_dir, "doc_files"))
    for doc_file, _ in doc_files:
        try:
            command = ["/usr/bin/python3", "/usr/bin/unoconv", "-f", "docx", doc_file]
            if run_unoconv(command, "转docx格式成功！", doc_file):
                docx_file = os.path.splitext(doc_file)[0] + ".docx"
                move_file(docx_file, output_dir)
                move_file(doc_file, os.path.join(converted_dir, "doc_files"))
        except Exception as e:
            print_log(e)

    print_log("所有 DOC 转 DOCX 完成！")

    if docx_files:
        output_dir = os.path.join(converted_dir, "docx_files")
        ensure_dir(output_dir)
        for docx_file, _ in docx_files:
            move_file(docx_file, output_dir)


def convert_docx_to_pdf(converted_dir):
    output_dir = os.path.join(converted_dir, "docx2pdf_files")
    ensure_dir(output_dir)
    docx_files = traverse_dir(os.path.join(converted_dir, "docx_files"), ['docx'])
    for docx_file, _ in docx_files:
        try:
            command = ["/usr/bin/python3", "/usr/bin/unoconv", "-f", "pdf", docx_file]
            if run_unoconv(command, "转pdf格式成功！", docx_file):
                pdf_file = os.path.splitext(docx_file)[0] + ".pdf"
                move_file(pdf_file, output_dir)
        except Exception as e:
            print_log(e)
    print_log("所有 docx 转 pdf 完成！")


def convert_doc_to_pdf(converted_dir):
    output_dir = os.path.join(converted_dir, "doc2pdf_files")
    ensure_dir(output_dir)
    doc_files = traverse_dir(os.path.join(converted_dir, "doc_files"), ['doc'])
    for doc_file, _ in doc_files:
        try:
            command = ["/usr/bin/python3", "/usr/bin/unoconv", "-f", "pdf", doc_file]
            if run_unoconv(command, "转pdf格式成功！", doc_file):
                pdf_file = os.path.splitext(doc_file)[0] + ".pdf"
                move_file(pdf_file, output_dir)
        except Exception as e:
            print(e)
    print_log("所有 doc 转 pdf 完成！")


def convert_pdf_to_docx(data_dir, converted_dir):
    output_dir = os.path.join(converted_dir, "pdf2docx_files")
    ensure_dir(output_dir)
    ensure_dir(os.path.join(converted_dir, "pdf_files"))
    pdf_files = traverse_dir(data_dir, ['pdf'])
    for file, file_uuid in pdf_files:
        try:
            output_file = os.path.join(output_dir, file_uuid + ".docx")
            pdf_parse(file, output_file)
            move_file(file, os.path.join(converted_dir, "pdf_files"))
        except Exception as e:
            print(e)


def convert_xls_to_xlsx(data_dir, converted_dir):
    output_dir = os.path.join(converted_dir, "xls2xlsx_files")
    ensure_dir(output_dir)
    ensure_dir(os.path.join(converted_dir, "xls_files"))
    xls_files = traverse_dir(data_dir, ['xls'])
    for file, file_uuid in xls_files:
        try:
            output_file = os.path.join(output_dir, file_uuid + ".xlsx")
            XLS2XLSX(file).to_xlsx(output_file)
            move_file(file, os.path.join(converted_dir, "xls_files"))
        except Exception as e:
            print_log(e)

    xlsx_files = traverse_dir(data_dir, ['xlsx'])
    ensure_dir(os.path.join(converted_dir, "xlsx_files"))
    for file, _ in xlsx_files:
        move_file(file, os.path.join(converted_dir, "xlsx_files"))


def convert_file(failed_ls, input_dir, converted_dir, converted_to_pdf=True):
    """
    转换目录下的文件至最新格式：
    1. 将 .doc 转换为 .docx 格式；
    2. 将 .pdf 转换为 .docx 格式；
    3. 将 .xls 转换为 .xlsx 格式；
    同时整理其他格式的文件至相应目录。
    """
    pdf_paths = set(i[1]+'.pdf' for i in traverse_dir(input_dir, ['pdf']))
    doc_paths = set(i[1]+'.doc' for i in traverse_dir(input_dir, ['doc']))
    xls_paths = set(i[1]+'.xls' for i in traverse_dir(input_dir, ['xls']))

    # DOC 转 DOCX
    convert_doc_to_docx(input_dir, converted_dir)
    # PDF 转 DOCX
    convert_pdf_to_docx(input_dir, converted_dir)
    # XLS 转 XLSX
    convert_xls_to_xlsx(input_dir, converted_dir)

    exs_pdf_paths = set(i[1]+'.pdf' for i in traverse_dir(os.path.join(converted_dir, 'pdf2docx_files'), None))
    exs_doc_paths = set(i[1]+'.doc' for i in traverse_dir(os.path.join(converted_dir, 'doc2docx_files'), None))
    exs_xls_paths = set(i[1]+'.xls' for i in traverse_dir(os.path.join(converted_dir, 'xls2xlsx_files'), None))

    converted_failed_ls = [
        {'filePath': i, 'reason': '文件格式转换失败'} for i in
        (pdf_paths - exs_pdf_paths) | (doc_paths - exs_doc_paths) | (xls_paths - exs_xls_paths)
    ]
    failed_ls.extend(converted_failed_ls)

    # 整理其他格式的文件
    other_dirs = {
        'ofd': "ofd_files",
        'txt': "txt_files",
        'xml': "xml_files",
        'img': "img_files"  # 统一处理图片文件，后续根据扩展名移动
    }
    # 创建目标目录
    for key in ['ofd', 'txt', 'xml']:
        ensure_dir(os.path.join(converted_dir, other_dirs[key]))
    # 处理 ofd, txt, xml 文件
    for ext, folder in [('ofd', 'ofd_files'), ('txt', 'txt_files'), ('xml', 'xml_files')]:
        files = traverse_dir(input_dir, [ext])
        for file, _ in files:
            move_file(file, os.path.join(converted_dir, folder))

    # 处理图片文件
    img_extensions = ['jpg', 'jpeg', 'png', 'jfif', 'exif', 'gif', 'tiff', 'bmp']
    ensure_dir(os.path.join(converted_dir, other_dirs['img']))
    img_files = traverse_dir(input_dir, img_extensions)
    for file, _ in img_files:
        move_file(file, os.path.join(converted_dir, other_dirs['img']))
    if converted_to_pdf:
        # DOCX 转 PDF 和 DOC 转 PDF
        convert_docx_to_pdf(converted_dir)
        convert_doc_to_pdf(converted_dir)
